package com.txy.domain.strategy.service.armory;

import com.txy.domain.strategy.model.entity.StrategyAwardEntity;
import com.txy.domain.strategy.model.entity.StrategyEntity;
import com.txy.domain.strategy.model.entity.StrategyRuleEntity;
import com.txy.domain.strategy.repository.IStrategyRepository;
import com.txy.types.exception.AppException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.SecureRandom;
import java.util.*;

import static com.txy.types.enums.ResponseCode.STRATEGY_RULE_WEIGHT_IS_NULL;

@Service
public class StrategyArmoryDispatch implements IStrategyArmory, IStrategyDispatch {
    @Resource
    private IStrategyRepository repository;

    @Override
    public boolean assembleLotteryStrategy(Long strategyId) {
        // 1. 查询策略配置 装配抽奖策略
        List<StrategyAwardEntity> strategyAwardEntities = repository.queryStrategyAwardList(strategyId);

        // 2. 装配奖品库存
        for (StrategyAwardEntity strategyAwardEntity : strategyAwardEntities) {
            // 缓存库存
            repository.storeStrategyStock(strategyId, strategyAwardEntity.getAwardId(), strategyAwardEntity.getAwardCount());
        }

        // 3.1. 普通装配
        assembleLotteryStrategy(String.valueOf(strategyId), strategyAwardEntities);


        // 3.2. 权重装配
        StrategyEntity strategyEntity = repository.queryStrategyByStrategyId(strategyId);
        String ruleWeight = strategyEntity.getRuleWeight();
        if (ruleWeight == null) {
            return true;
        }

        StrategyRuleEntity strategyRuleEntity = repository.queryStrategyRule(strategyId, ruleWeight);
        if (strategyRuleEntity == null) {
            throw new AppException(STRATEGY_RULE_WEIGHT_IS_NULL.getCode(), STRATEGY_RULE_WEIGHT_IS_NULL.getInfo());
        }

        // 4. 权重规则类型不同积分的奖品重新装配抽奖策略
        Map<String, List<Integer>> ruleWeightValues = strategyRuleEntity.getRuleWeightValues();
        ruleWeightValues.forEach((key, value) -> {
            List<StrategyAwardEntity> strategyAwardEntitiesClone = new ArrayList<>(strategyAwardEntities);
            strategyAwardEntitiesClone.removeIf(entity -> !value.contains(entity.getAwardId()));
            assembleLotteryStrategy(String.valueOf(strategyId).concat("_").concat(key), strategyAwardEntitiesClone);
        });

        return true;
    }

    private void assembleLotteryStrategy(String key, List<StrategyAwardEntity> strategyAwardEntities) {
        // 1. 获取抽奖奖品概率最小值
        BigDecimal minAwardRate = strategyAwardEntities.stream()
                .map(StrategyAwardEntity::getAwardRate)
                .min(BigDecimal::compareTo)
                .orElse(BigDecimal.ZERO);

        // 2. 获取概率值总和
        BigDecimal totalAwardRate = strategyAwardEntities.stream()
                .map(StrategyAwardEntity::getAwardRate)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 3. 用1 / 0.0001 获取概率范围
        BigDecimal rateRange = totalAwardRate.divide(minAwardRate, 0, RoundingMode.CEILING);

        // 4. 填充奖品策略数组
        ArrayList<Integer> strategyAwardSearchRateTables = new ArrayList<>(rateRange.intValue());
        for (StrategyAwardEntity strategyAwardEntity : strategyAwardEntities) {
            Integer awardId = strategyAwardEntity.getAwardId();
            BigDecimal awardRate = strategyAwardEntity.getAwardRate();
            for (int i = 0; i < awardRate.multiply(rateRange).setScale(0, RoundingMode.CEILING).intValue(); i ++ ) {
                strategyAwardSearchRateTables.add(awardId);
            }
        }

        // 5. 乱序
        Collections.shuffle(strategyAwardSearchRateTables);

        // 6. 转换为奖品策略hash表
        HashMap<Integer, Integer> shuffleStrategyAwardSearchRateTables = new HashMap<>();
        for (int i = 0; i < strategyAwardSearchRateTables.size(); i++) {
            shuffleStrategyAwardSearchRateTables.put(i, strategyAwardSearchRateTables.get(i));
        }

        // 7. 保存redis
        repository.storeStrategyAwardSearchRateTable(key, strategyAwardSearchRateTables.size(), shuffleStrategyAwardSearchRateTables);

    }

    @Override
    public Integer getRandomAwardId(Long strategyId) {
        // 1. 获取概率范围
        Integer rateRange = repository.getRateRange(String.valueOf(strategyId));

        // 2. 获取抽奖奖品
        return repository.getStragegyAwardAssemble(String.valueOf(strategyId), new SecureRandom().nextInt(rateRange));
    }

    @Override
    public Integer getRandomAwardId(Long strategyId, String weightRuleValue) {
        String key = String.valueOf(strategyId).concat("_").concat(weightRuleValue);

        // 1. 获取概率范围
        Integer rateRange = repository.getRateRange(key);

        // 2. 获取抽奖奖品
        return repository.getStragegyAwardAssemble(key, new SecureRandom().nextInt(rateRange));
    }

    @Override
    public Boolean subtractionAwardStock(Long strategyId, Integer awardId) {
        // 库存扣减
        return repository.subtractionAwardStock(strategyId, awardId);
    }
}
